/**
 * 
 */
package net.mysoftworks.bm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;

/**
 * @author <div style="width: 100%; height: 2em;
 * background-repeat: repeat-x; 
 * background-image: url(http://www.mysoftworks.net/images/author_back.gif);" >
 * <a style="float: right; font-size: .9em; margin: 1.2em .5em .1em .1em; color: #658A16; color: 658A16; font-family: helvetica; font-weight: bold; text-decoration: none" href="http://www.mysoftworks.net">
 * Antonio Giovannetti </a>
 * </div>
 */
public class BackupManager {

	private enum FileSizeMatchType {GREATER,SMALLER};
	
	private String sourceFolder;
	private String destFolder;
	private String filename;
	private String patternMatch;
	private String patternNotMatch;
	private FilenameFilter _fileFilter ;
	
	private List<File> list = new ArrayList<File>();
	
	private void deleteRecursive(File file) throws Exception {
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (File sub : files) {
				deleteRecursive(sub);
			}
		}
		if (!file.delete()) throw new Exception("Cannot delete " + file.getAbsolutePath());
		
	}
	
	
	public BackupManager(String sourceFolder,String destFolder,String filename,String patternMatch,String patternNotMatch) {
		this.sourceFolder = sourceFolder;
		this.destFolder = (destFolder == null) ? sourceFolder : destFolder;
		this.filename = filename;
		this.patternMatch = patternMatch;
		this.patternNotMatch = patternNotMatch;
	}
	
	private void _innerListFolder(String srcFolder,boolean recursive) {
		File[] sources = scanFolder(srcFolder);
		if(sources == null) return;
		for (int i = 0; i < sources.length; i++) {
			if (sources[i].isDirectory() && recursive) {
				_innerListFolder(sources[i].getAbsolutePath(),recursive);
			}
			else {
				if (sources[i].isFile()) list.add(sources[i]); 
			}
		}
	}

	
	private long getFileSize(File file) {
//		System.out.println("isFile: " + file.isFile());
//		System.out.println("isDirectory: " + file.isDirectory());
		if (file.isFile()) return file.length();
		long size = 0L;
		if (file.isDirectory()) {
			File[] files = file.listFiles(new NoSVNFileFilter());
			if (files!=null) {
				for (File sub : files) {
					size+=getFileSize(sub);
				}
			}	
		}
		return size;
		
	}
	
	private void setDefaultFileFilter() {
		_fileFilter = new FilenameAndPatternFilter(filename,patternMatch,patternNotMatch);
	}

	
	private void setSizeFileFilterRange(final long lowerSize, final long higherSize) {
		_fileFilter = new FilenameAndPatternFilter(filename,patternMatch,patternNotMatch) {
			public boolean accept(File dir, String name) {
				boolean accept = super.accept(dir, name);
				File inner = new File(dir,name);
				long s = -1;
				if (accept && inner.isFile()) {
					s = getFileSize(inner);
//					System.out.println("Size for " + name + " is " + s + ", ref is " + size);
					accept = accept && (s>lowerSize && s<higherSize); 
				}
				return accept;
			}
		};
	}

	
	private void setSizeFileFilter(final long size, final FileSizeMatchType type) {
		_fileFilter = new FilenameAndPatternFilter(filename,patternMatch,patternNotMatch) {
			public boolean accept(File dir, String name) {
				boolean accept = super.accept(dir, name);
				File inner = new File(dir,name);
				long s = -1;
				if (accept && inner.isFile()) {
					s = getFileSize(inner);
//					System.out.println("Size for " + name + " is " + s + ", ref is " + size);
					accept = accept && (type.equals(FileSizeMatchType.SMALLER)) ? (s<size) : (s>size); 
				}
				return accept;
			}
		};
	}
	
	
	public File[] scanFolder(String srcFolder) {
		File folder = new File(srcFolder);
		File[] result = folder.listFiles(_fileFilter);
		return result;
	}
	
	private void logMessage(String message,long sleep) {
		int len = 100;
		int half = len/2;
		int delta = 20;
		String separator = StringUtils.repeat("=", len);
		System.out.println(separator);
		System.out.println(separator);
		System.out.println(separator);
		String regexp = "(.{"+(half - delta)+"}[.^\\S]{0,"+ delta + "})";
		String msg = message.toUpperCase().replaceAll(regexp, "$1\n");
		String[] msgs =msg.split("\n");
		for (int i = 0; i < msgs.length; i++) {
			System.out.println(StringUtils.center(msgs[i].replaceAll("(.)", " $1"), len,'='));
		}
		System.out.println(separator);
		System.out.println(separator);
		System.out.println(separator);
		try {
			Thread.sleep(sleep);
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	
	public void clean(long size, FileSizeMatchType type) {
		// La stessa istruzone da riga di comando
		// find /media/DATA/antonio/sbackup -path "*.tar.gz" -size -5k | grep -Eo .*inc | xargs rm -r

		
		StringBuilder s = new StringBuilder("about to clean files ");
		s.append(type.name());
		s.append(" then ");
		s.append(size).append(" bytes");
		s.append(" in folder ").append(sourceFolder);
		s.append(" that match ").append(patternMatch);
		s.append(" and not match ").append(patternNotMatch);
		logMessage(s.toString(), 2000);
		setSizeFileFilter(size,type);
		_innerListFolder(sourceFolder,true);
		for (File f: list) {
			try {
				System.out.print("\tdeleting "+f.getParentFile() + "....");
				deleteRecursive(f.getParentFile());
				System.out.println("OK");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
//			System.out.println("\tabout to delete "+f.getParentFile());
		}
	} 
	

	private boolean testExtract(TarEntry tarEntry) {
		if (tarEntry==null) return false;
		String entryName = tarEntry.getName().toLowerCase();
		return !tarEntry.isDirectory() && !entryName.matches(".exe") && !entryName.endsWith(".cab") && !entryName.endsWith(".xst");
	}
	
	
	
	private void doUnzipFile(File f,File dfolder ) throws Exception {
		String prefix=f.getParentFile().getName();
		
//		File folder = new File(new File(destFolder),"content" + prefix + "/");
//		if (!folder.exists() && folder.mkdir()) {
			GZIPInputStream gz = new GZIPInputStream(new FileInputStream(f));
			TarInputStream taris = new TarInputStream(gz);
			TarEntry tarEntry = taris.getNextEntry();
			while (tarEntry != null){
				String entryName = tarEntry.getName().toLowerCase();
				if (testExtract(tarEntry)) {
					String ext = FilenameUtils.getExtension(entryName);
					File saved = File.createTempFile(prefix, "." + ext,dfolder);
					System.out.println("\t\tSaving to " + saved.getAbsolutePath());
					taris.copyEntryContents(new FileOutputStream(saved));
				}
				tarEntry = taris.getNextEntry();
				
			}
			gz.close();
//		}
		
	}

	
	
	
	public void unzipToFolder(long from, long to,boolean cleanBefore) {
		StringBuilder s = new StringBuilder("about to unzip files");
		logMessage(s.toString(), 0);
//		setSizeFileFilter(15*1024,FileSizeMatchType.SMALLER);
		setSizeFileFilterRange(from,to);
		_innerListFolder(sourceFolder,true);
		File folder = new File(destFolder);

		if (cleanBefore) 
			try {
				FileUtils.cleanDirectory(folder);
			} catch (Exception e) {
				// TODO: handle exception
			}
		for (File f: list) {
			try {
				System.out.print("\tunzipping "+f.getAbsolutePath() + "....");
				doUnzipFile(f,folder);
				System.out.println("OK");
			} catch (Exception e) {
				e.printStackTrace();
				// TODO: handle exception
			}
//			System.out.println("\tabout to unzip "+f);
		}
		
		
		
	} 
	
	

	
	public void startMove(boolean deleteOld) {
		logMessage("ABOUT TO MOVE", 2000);
		setDefaultFileFilter();
		_innerListFolder(sourceFolder,true);
		new File(destFolder).mkdirs();
		for (File f: list) {
			String newFilename = f.getParentFile().getName()+".tar.gz";
			newFilename  = newFilename.replaceAll("linux-363x\\.site\\.", "");
			File dest = new File(destFolder,newFilename);
			if (true && f.renameTo(dest)) {
				if (deleteOld) {
					try {
						System.out.print("\t" + f.getParentFile()+ "....");
						deleteRecursive(f.getParentFile());
						System.out.println("OK");
						
					} catch (Exception e) {
						e.printStackTrace();
					}
				}	
			} else {
				System.out.println("\tabout to delete "+f.getParentFile());
			}
			
		}
		
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		String expression = "ReportUtils.getReport(\"asfgsafg\"";
		System.out.println(expression.replaceAll(".*\"(.*)\"", "$1"));
		
		
//		if (true) return;
		
		
		
//		String sourceFolder = "/media/SYSTEM/antonio/eng2/sbackup";
		String sourceFolder = "/home/antonio/data/sbackup";
		String destFolder = "/home/antonio/tempo/";// sourceFolder;
		String filename = "files.tar.gz";
		String patternMatch = null; //".*2011-06-24.*";
		String patternNotMatch = ".*\\.ful$";
		
//		find /media/DATA/antonio/sbackup -path "*.tar.gz" -size -5k | grep -Eo .*inc | xargs rm -r
//		0,5,10,15,20,25,30,35,40,45,50,55
//		System.out.println(sourceFolder.replaceAll("(.)", "$1 "));
//		
//		System.out.println(StringUtils.center("abcde".toUpperCase().replaceAll("(.)", " $1 "), 30,'='));
		
		
//		boolean res=evalA();
//		res = res && evalB();
//		System.out.println("res:" + res);
		
		BackupManager bm = new BackupManager(sourceFolder,destFolder,filename,patternMatch,patternNotMatch);
		
//		bm.startMove(true);
//		bm.clean(5*1024,FileSizeMatchType.SMALLER);
		bm.unzipToFolder(5*1024,1024*1024*1024,false);  // from 5k to 1M
		
		
//		System.out.println(bm.getFileSize(new File("/home/antonio/temp/")));
	}




}
